﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace Just4Devs.Vsirc.Addin.UI
{
	/// <summary>
	/// Mediates requests to the user interface.
	/// </summary>
	public class VsircScreenDirector
	{
		private TabControl tabControl;
		private Dictionary<string, IVsircTab> _tabs;
		private VsircController _controller;

		/// <summary>
		/// Initializes a new instance of the <see cref="VsircScreenDirector"/> class.
		/// </summary>
		/// <param name="tabControl">The tab control.</param>
		public VsircScreenDirector(TabControl tabControl)
		{
			this.tabControl = tabControl;

			_tabs = new Dictionary<string, IVsircTab>();
			_controller = new VsircController(this);
			tabControl.Selected += new TabControlEventHandler(tabControl_Selected);
		}

		void tabControl_Selected(object sender, TabControlEventArgs e)
		{
			GetTab(e.TabPage.Name).UnreadMessages = 0;
		}

		/// <summary>
		/// Directs the message to the specified tab to be printed
		/// on the screen.
		/// </summary>
		/// <param name="destinatary">Name of the receiver tab.</param>
		/// <param name="message">The message.</param>
		public void RouteMessage(string destinatary, ScreenMessage message)
		{
			var receiverTab = GetTab(destinatary);
			receiverTab.HandleMessage(message);

			MessageDirected(receiverTab);
		}

		/// <summary>
		/// Directs the message to current tab to be printed
		/// on the screen.
		/// </summary>
		/// <param name="message">The message.</param>
		public void DirectMessageToTab(ScreenMessage message)
		{
			GetCurrentTab().HandleMessage(message);
		}

		/// <summary>
		/// Sets the channel user list.
		/// </summary>
		/// <param name="channelName">Name of the channel.</param>
		/// <param name="users">The users.</param>
		public void SetChannelUserList(string channelName, string[] users)
		{
			var channel = (VsircChannelTab)GetTab(channelName);
			channel.SetUserList(users);
		}

		/// <summary>
		/// Sets the current tab.
		/// </summary>
		/// <param name="tabName">Name of the tab.</param>
		public void SelectTab(string tabName)
		{
			SelectTab(GetTab(tabName));
		}

		/// <summary>
		/// Removes the tab.
		/// </summary>
		/// <param name="tabName">Name of the tab.</param>
		public void RemoveTab(string tabName)
		{
			var tab = GetTab(tabName);

			if (tab != null)
			{
				RemoveTab(tab);
			}
		}

		/// <summary>
		/// Removes all tabs except the server tab.
		/// </summary>
		public void RemoveAllTabs()
		{
			var tabs = _tabs.Where(kvp => kvp.Key != GetTabKeyFromTabName(_controller.ServerName)).Select(kvp => kvp.Value).ToList();

			foreach (var tab in tabs)
			{
				RemoveTab(tab);
			}
		}

		/// <summary>
		/// Closes the current tab.
		/// </summary>
		public void CloseCurrentTab()
		{
			try
			{
				var serverTabName = _controller.ServerName;

				if (string.IsNullOrEmpty(serverTabName))
				{
					return;
				}

				var currentTab = GetCurrentTab();
				var serverTab = (IVsircTab)GetTab(serverTabName);

				if (currentTab != serverTab)
				{
					if (currentTab is VsircPrivateConversation)
					{
						RemoveTab(currentTab);
					}
					else if (currentTab is VsircChannelTab)
					{
						_controller.Part(currentTab.Name);
					}
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// Requests the message dispatch.
		/// </summary>
		/// <param name="message">The message.</param>
		public void RequestMessageDispatch(string message)
		{
			_controller.SendMessage(GetCurrentTab().Name, message);
		}

		/// <summary>
		/// Requests the connect.
		/// </summary>
		public void RequestConnect()
		{
			_controller.Connect();
		}

		/// <summary>
		/// Requests the disconnect.
		/// </summary>
		public void RequestDisconnect()
		{
			_controller.Disconnect();
		}

		protected void MessageDirected(IVsircTab receiverTab)
		{
			var castedTab = ((TabPage)receiverTab);
			tabControl.UIThreadInvoke(() =>
			{
				if (!tabControl.SelectedTab.Equals(castedTab))
				{
					receiverTab.UnreadMessages++;
				}
			});
		}

		/// <summary>
		/// Sets the current tab.
		/// </summary>
		/// <param name="tab">The tab.</param>
		protected void SelectTab(IVsircTab tab)
		{
			tabControl.UIThreadInvoke(() => tabControl.SelectedTab = (TabPage)tab);
		}

		/// <summary>
		/// Removes the tab.
		/// </summary>
		/// <param name="tab">The tab.</param>
		protected void RemoveTab(IVsircTab tab)
		{
			if (tab != null)
			{
				tabControl.Controls.Remove((TabPage)tab);
				_tabs.Remove(GetTabKeyFromTabName(tab.Name));
			}
		}

		/// <summary>
		/// Gets the name of the tab key from tab.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <returns>
		/// The value to be used as key in the tab collection.
		/// </returns>
		protected string GetTabKeyFromTabName(string name)
		{
			return name.ToLowerInvariant();
		}

		/// <summary>
		/// Gets the current tab.
		/// </summary>
		/// <returns>
		/// The currently selected tab.
		/// </returns>
		protected IVsircTab GetCurrentTab()
		{
			return _tabs[GetTabKeyFromTabName(tabControl.SelectedTab.Name)];
		}

		/// <summary>
		/// Gets an existing tab or creates one with the specified name.
		/// </summary>
		/// <param name="name">The tab name.</param>
		/// <returns>
		/// A channel or private tab instance (according to its name).
		/// </returns>
		protected IVsircTab GetTab(string name)
		{
			IVsircTab returningTab = null;
			var tabKey = GetTabKeyFromTabName(name);

			if (_tabs.ContainsKey(tabKey))
			{
				returningTab = _tabs[tabKey];
			}
			else
			{
				returningTab = CreateTab(name);
			}

			return returningTab;
		}

		protected IVsircTab CreateTab(string name)
		{
			var newTab = new VsircTabFactory().CreateTab(name, this);

			_tabs.Add(GetTabKeyFromTabName(name), newTab);
			tabControl.UIThreadInvoke(() => tabControl.Controls.Add((TabPage)newTab));

			return newTab;
		}
	}
}
